<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
    />
    <meta name="description" content="Particle system fireworks." />
    <meta name="cesium-sandcastle-labels" content="Beginner, Showcases" />
    <title>Cesium Demo</title>
    <script type="text/javascript" src="../Sandcastle-header.js"></script>
    <script
      type="text/javascript"
      src="../../../Build/CesiumUnminified/Cesium.js"
      nomodule
    ></script>
    <script type="module" src="../load-cesium-es6.js"></script>
  </head>
  <body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html">
    <style>
      @import url(../templates/bucket.css);
    </style>
    <div id="cesiumContainer" class="fullSize"></div>
    <div id="loadingOverlay"><h1>Loading...</h1></div>
    <div id="toolbar"></div>
    <script id="cesium_sandcastle_script">
      window.startup = async function (Cesium) {
        "use strict";
        //Sandcastle_Begin
        const viewer = new Cesium.Viewer("cesiumContainer", {
          shouldAnimate: true,
        });

        const scene = viewer.scene;
        scene.debugShowFramesPerSecond = true;

        Cesium.Math.setRandomNumberSeed(315);

        const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(
          Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
        );
        const emitterInitialLocation = new Cesium.Cartesian3(0.0, 0.0, 100.0);

        let particleCanvas;

        function getImage() {
          if (!Cesium.defined(particleCanvas)) {
            particleCanvas = document.createElement("canvas");
            particleCanvas.width = 20;
            particleCanvas.height = 20;
            const context2D = particleCanvas.getContext("2d");
            context2D.beginPath();
            context2D.arc(8, 8, 8, 0, Cesium.Math.TWO_PI, true);
            context2D.closePath();
            context2D.fillStyle = "rgb(255, 255, 255)";
            context2D.fill();
          }
          return particleCanvas;
        }

        const minimumExplosionSize = 30.0;
        const maximumExplosionSize = 100.0;
        const particlePixelSize = new Cesium.Cartesian2(7.0, 7.0);
        const burstSize = 400.0;
        const lifetime = 10.0;
        const numberOfFireworks = 20.0;

        const emitterModelMatrixScratch = new Cesium.Matrix4();

        function createFirework(offset, color, bursts) {
          const position = Cesium.Cartesian3.add(
            emitterInitialLocation,
            offset,
            new Cesium.Cartesian3(),
          );
          const emitterModelMatrix = Cesium.Matrix4.fromTranslation(
            position,
            emitterModelMatrixScratch,
          );
          const particleToWorld = Cesium.Matrix4.multiply(
            modelMatrix,
            emitterModelMatrix,
            new Cesium.Matrix4(),
          );
          const worldToParticle = Cesium.Matrix4.inverseTransformation(
            particleToWorld,
            particleToWorld,
          );

          const size = Cesium.Math.randomBetween(
            minimumExplosionSize,
            maximumExplosionSize,
          );
          const particlePositionScratch = new Cesium.Cartesian3();
          const force = function (particle) {
            const position = Cesium.Matrix4.multiplyByPoint(
              worldToParticle,
              particle.position,
              particlePositionScratch,
            );
            if (Cesium.Cartesian3.magnitudeSquared(position) >= size * size) {
              Cesium.Cartesian3.clone(Cesium.Cartesian3.ZERO, particle.velocity);
            }
          };

          const normalSize =
            (size - minimumExplosionSize) / (maximumExplosionSize - minimumExplosionSize);
          const minLife = 0.3;
          const maxLife = 1.0;
          const life = normalSize * (maxLife - minLife) + minLife;

          scene.primitives.add(
            new Cesium.ParticleSystem({
              image: getImage(),
              startColor: color,
              endColor: color.withAlpha(0.0),
              particleLife: life,
              speed: 100.0,
              imageSize: particlePixelSize,
              emissionRate: 0,
              emitter: new Cesium.SphereEmitter(0.1),
              bursts: bursts,
              lifetime: lifetime,
              updateCallback: force,
              modelMatrix: modelMatrix,
              emitterModelMatrix: emitterModelMatrix,
            }),
          );
        }

        const xMin = -100.0;
        const xMax = 100.0;
        const yMin = -80.0;
        const yMax = 100.0;
        const zMin = -50.0;
        const zMax = 50.0;

        const colorOptions = [
          {
            minimumRed: 0.75,
            green: 0.0,
            minimumBlue: 0.8,
            alpha: 1.0,
          },
          {
            red: 0.0,
            minimumGreen: 0.75,
            minimumBlue: 0.8,
            alpha: 1.0,
          },
          {
            red: 0.0,
            green: 0.0,
            minimumBlue: 0.8,
            alpha: 1.0,
          },
          {
            minimumRed: 0.75,
            minimumGreen: 0.75,
            blue: 0.0,
            alpha: 1.0,
          },
        ];

        for (let i = 0; i < numberOfFireworks; ++i) {
          const x = Cesium.Math.randomBetween(xMin, xMax);
          const y = Cesium.Math.randomBetween(yMin, yMax);
          const z = Cesium.Math.randomBetween(zMin, zMax);
          const offset = new Cesium.Cartesian3(x, y, z);
          const color = Cesium.Color.fromRandom(colorOptions[i % colorOptions.length]);

          const bursts = [];
          for (let j = 0; j < 3; ++j) {
            bursts.push(
              new Cesium.ParticleBurst({
                time: Cesium.Math.nextRandomNumber() * lifetime,
                minimum: burstSize,
                maximum: burstSize,
              }),
            );
          }

          createFirework(offset, color, bursts);
        }

        const camera = viewer.scene.camera;
        const cameraOffset = new Cesium.Cartesian3(-300.0, 0.0, 0.0);
        camera.lookAtTransform(modelMatrix, cameraOffset);
        camera.lookAtTransform(Cesium.Matrix4.IDENTITY);

        const toFireworks = Cesium.Cartesian3.subtract(
          emitterInitialLocation,
          cameraOffset,
          new Cesium.Cartesian3(),
        );
        Cesium.Cartesian3.normalize(toFireworks, toFireworks);
        const angle =
          Cesium.Math.PI_OVER_TWO -
          Math.acos(Cesium.Cartesian3.dot(toFireworks, Cesium.Cartesian3.UNIT_Z));
        camera.lookUp(angle);
        //Sandcastle_End
      };
      if (typeof Cesium !== "undefined") {
        window.startupCalled = true;
        window.startup(Cesium).catch((error) => {
          "use strict";
          console.error(error);
        });
        Sandcastle.finishedLoading();
      }
    </script>
  </body>
</html>
